﻿using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.AccessControl;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;

namespace Install
{
    public class ProgramInstall
    {
        private int mode = 0;
        private string pathFile = @"files\";
        private string pathRoot;
        //private bool isOk = false;
        /// <summary>
        /// 安装程序
        /// </summary>
        /// <param name="path"></param>
        /// <param name="mode">1:新装 2:修复</param>
        public ProgramInstall(string path, int mode)
        {
            pathRoot = path;
            this.mode = mode;
            Thread thread = new Thread(StartInstall);
            thread.IsBackground = true;
            thread.Start();
        }

        void StartInstall()
        {
            while (MainWindow.instance.Doing)
            {
                Thread.Sleep(100);
            }
            try
            {
                MainWindow.instance.Doing = true;
                MainWindow.instance.OutputMsg("开始安装...");
                CopyFiles(pathFile, pathRoot);
                RegexSet();
                Shotcut();
                //SetPathPower(pathRoot, Environment.UserName, "FullControl");
                SetSecurty(pathRoot, Environment.UserName);
                RunStart();
                RunNotify();
                //this.Service();
                //this.FirewallSet();
                MainWindow.instance.OutputMsg("程序安装完成。");
            }
            catch (Exception e)
            {
                MainWindow.instance.OutputErr("错误：" + e.Message);
            }
            MainWindow.instance.Doing = false;
        }

        /// <summary>
        /// 复制目录及子目录的所有文件
        /// </summary>
        /// <param name="srcdir">要复制的文件所在的目录</param>
        /// <param name="desdir">复制到的目录</param>
        public void CopyFiles(string srcdir, string desdir)
        {
            MainWindow.instance.OutputMsg("开始复制文件...");
            //string folderName = srcdir.Substring(srcdir.LastIndexOf("\\") + 1);
            //string desfolderdir = desdir + "\\" + folderName;
            string folderName = srcdir.Substring(srcdir.LastIndexOf("\\") + 1);
            string desfolderdir = desdir + "\\" + folderName;
            if (desdir.LastIndexOf("\\") == (desdir.Length - 1))
            {
                desfolderdir = desdir + folderName;
            }
            string[] filenames = Directory.GetFileSystemEntries(srcdir);
            
            foreach (string file in filenames)// 遍历所有的文件和目录
            {
                if (Directory.Exists(file))// 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件
                {
                    string currentdir = desfolderdir + file.Substring(file.LastIndexOf("\\") + 1);
                    if (!Directory.Exists(currentdir))
                    {
                        Directory.CreateDirectory(currentdir);
                    }
                    if(file.Length >= 10 && file.Substring(file.Length - 10, 10).Equals("Config.xml"))
                    {
                        continue;
                    }
                    CopyFiles(file, desfolderdir);
                }
                else // 否则直接copy文件
                {
                    string srcfileName = file.Substring(file.LastIndexOf("\\") + 1);
                    srcfileName = desfolderdir + srcfileName;
                    if (!Directory.Exists(desfolderdir))
                    {
                        Directory.CreateDirectory(desfolderdir);
                    }
                    if(mode == 1)//新装
                    {
                        if (file.Length >= 10 && file.Substring(file.Length - 10, 10).Equals("Config.xml"))
                        {
                            continue;
                        }
                    }else if(mode == 2)//修复
                    {
                        if (Regex.IsMatch(srcfileName, "^.*\\.xml$"))
                        {
                            //MainWindow.instance.OutputMsg("忽略： " + srcfileName);
                            continue;
                        }
                    }
                    File.Copy(file, srcfileName);
                    MainWindow.instance.OutputMsg("复制: " + file);
                }
            }
            MainWindow.instance.OutputMsg("文件复制完成。");
        }

        private void RegexSet()
        {
            RegistryKey regRoot = Registry.CurrentUser;
            RegistryHelper reg = new RegistryHelper();
            MainWindow.instance.OutputMsg("正在设置注册表...");
            try
            {
                reg.SetRegistryData(regRoot, "SOFTWARE\\SFJDManagement", "RootPath", this.pathRoot);
                reg.SetRegistryData(regRoot, "SOFTWARE\\SFJDManagement", "TempPath", Path.GetTempPath());
                MainWindow.instance.OutputMsg("注册表设置完成。");
            }
            catch(Exception e)
            {
                MainWindow.instance.OutputErr(e.Message);
            }
        }

        private void RunStart()
        {
            MainWindow.instance.OutputMsg("设置开机启动...");
            RunWhenStart(true, "司法鉴定助手", pathRoot + "\\SFJDTray.exe");
            MainWindow.instance.OutputMsg("设置开机启动完成。");
        }

        private void RunNotify()
        {
            Process p = new Process();
            p.StartInfo.FileName = pathRoot + "\\SFJDTray.exe";
            p.Start();
        }

        private void Service()
        {
            MainWindow.instance.OutputMsg("正在安装Windows服务...");
            ServiceHelper.InstallmyService(null, this.pathRoot + "\\SFJDService.exe");
            MainWindow.instance.OutputMsg("正在设置服务...");
            ServiceHelper.ChangeServiceStartType(2, "SFJDService");
            MainWindow.instance.OutputMsg("正在启动服务...");
            ServiceHelper.Start("SFJDService");
            MainWindow.instance.OutputMsg("服务启动完成。");
        }

        private void Shotcut()
        {
            string DesktopPath = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);//得到桌面文件夹
            string SendToPath = Environment.GetFolderPath(Environment.SpecialFolder.SendTo);//得到桌面文件夹
            

            // 声明操作对象
            IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
            // 创建一个快捷方式
            IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(DesktopPath + "\\司法鉴定.lnk");
            // 关联的程序
            shortcut.TargetPath = pathRoot + "\\SFJDManagement.exe";
            // 参数
            shortcut.Arguments = "";
            // 快捷方式描述，鼠标放到快捷方式上会显示出来哦
            shortcut.Description = "司法鉴定管理程序";
            // 全局热键
            //shortcut.Hotkey = "";
            // 设置快捷方式的图标，这里是取程序图标，如果希望指定一个ico文件，那么请写路径。
            //shortcut.IconLocation = pathRoot + "SFJDManagement.exe, 0";
            // 保存，创建就成功了。
            shortcut.Save();
            MainWindow.instance.OutputMsg("创建主程序的桌面快捷方式。");

            IWshRuntimeLibrary.WshShell shell2 = new IWshRuntimeLibrary.WshShell();
            IWshRuntimeLibrary.IWshShortcut shortcut2 = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(SendToPath + "\\～文件传送器.lnk");
            shortcut2.TargetPath = pathRoot + "\\Transport.exe";
            shortcut2.Arguments = "";
            shortcut2.Description = "发送文件到其他人";
            //shortcut2.Hotkey = "";
            //shortcut.IconLocation = pathRoot + "Transport.exe, 0";
            shortcut2.Save();
            MainWindow.instance.OutputMsg("创建文件传送器的右键菜单。");
        }

        /// <summary>
        /// 设置文件夹读写权限
        /// </summary>
        /// <param name="path"></param>
        /// <param name="userName"></param>
        public void SetSecurty(string path, string userName)
        {
            MainWindow.instance.OutputMsg("设置文件夹读写权限。");
            //获取文件夹信息
            DirectoryInfo dir = new DirectoryInfo(path);
            //获得该文件夹的所有访问权限
            DirectorySecurity dirSecurity = dir.GetAccessControl(AccessControlSections.All);
            //判断文件夹是否可以读写
            if (HasOperationPermission(path))
            {
                //设定文件ACL继承
                InheritanceFlags inherits = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
                //添加ereryone用户组的访问权限规则 完全控制权限
                //FileSystemAccessRule everyoneFileSystemAccessRule = new FileSystemAccessRule("Everyone", FileSystemRights.FullControl, inherits, PropagationFlags.None, AccessControlType.Allow);
                //添加Users用户组的访问权限规则 完全控制权限
                FileSystemAccessRule usersFileSystemAccessRule = new FileSystemAccessRule(userName, FileSystemRights.FullControl, inherits, PropagationFlags.None, AccessControlType.Allow);
                bool isModified = false;
                //dirSecurity.ModifyAccessRule(AccessControlModification.Add, everyoneFileSystemAccessRule, out isModified);
                dirSecurity.ModifyAccessRule(AccessControlModification.Add, usersFileSystemAccessRule, out isModified);
                //设置访问权限
                dir.SetAccessControl(dirSecurity);
            }
            else
            {
                MainWindow.instance.OutputMsg(dir + " 可以读写");
            }
        }

        /// <summary>
        /// 检查当前用户是否拥有此文件夹的操作权限
        /// </summary>
        /// <param name="folder"></param>
        /// <returns></returns>
        public bool HasOperationPermission(string folder)
        {
            var currentUserIdentity = Path.Combine(Environment.UserDomainName, Environment.UserName);

            DirectorySecurity fileAcl = Directory.GetAccessControl(folder);
            var userAccessRules = fileAcl.GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount)).OfType<FileSystemAccessRule>().Where(i => i.IdentityReference.Value == currentUserIdentity).ToList();

            return userAccessRules.Any(i => i.AccessControlType == AccessControlType.Deny);
        }

        /// <summary>
        /// 设置开机启动
        /// </summary>
        /// <param name="Started">是否启动</param>
        /// <param name="name">启动值的名称</param>
        /// <param name="path">启动程序的路径</param>
        private void RunWhenStart(bool Started, string name, string path)
        {
            RegistryKey HKLM = Registry.LocalMachine;
            RegistryKey Run = HKLM.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run");
            if (Started == true)
            {
                try
                {
                    Run.SetValue(name, path);
                    HKLM.Close();
                }
                catch (Exception Err)
                {
                    MessageBox.Show(Err.Message.ToString()); 
                }
            }
            else
            {
                try
                {
                    Run.DeleteValue(name);
                    HKLM.Close();
                }
                catch (Exception)
                {
                    // 
                }
            }
        }
    }
}
